package com.winner.data.util;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

import com.alibaba.fastjson.JSON;
import com.winner.data.entity.User;

import cn.hutool.core.text.StrPool;
import cn.hutool.core.util.StrUtil;

/**
 * java8 list分组转为map, 根据入参多字段动态分组
 *
 * @author wangxinle5
 * @since 2023-09-27
 */
public class GroupToMapUtil {

    public static void main(String[] args) {

        List<User> userList = Arrays.asList(new User(1L, "张三"), new User(2L, "李四"));

        // 用于将所有提取的name收集成一个列表
        Map<String, List<String>> groupedBy = userList.stream()
            .collect(Collectors.groupingBy(User::getName, Collectors.mapping(User::getName, Collectors.toList())));

        // 根据一个字段分组
        Map<String, List<User>> mapBy = userList.stream().collect(Collectors.groupingBy(User::getName));

        // 根据多个字段分组
        Map<String, List<User>> mapBy2 =
            userList.stream().collect(Collectors.groupingBy(user -> user.getName() + user.getId()));

        mapBy2.forEach((k, v) -> {
            System.out.println(k + JSON.toJSONString(v));
        });

        // 调用工具类, 可以根据入参多字段动态分组
        Map<String, List<User>> stringListMap = groupByProperty(userList, Arrays.asList("id", "name"));
        System.out.println(stringListMap);

        String name = userList.stream().findFirst().map(a -> getPropertyValue(a, Arrays.asList("name"))).orElse(null);
        System.out.println(name);

    }

    /**
     * 根据入参多字段对list分组操作
     *
     * @param list 要分组的list
     * @param willGroupList 需要分组的字段
     * @return 结果
     */
    public static <T> Map<String, List<T>> groupByProperty(List<T> list, List<String> willGroupList) {
        return list.stream().collect(Collectors.groupingBy(item -> getPropertyValue(item, willGroupList)));
    }

    /**
     * 根据入参多个属性, 获取对象属性的值, 用来替代 a -> a.getId + a.getName
     *
     * @param item 实体对象
     * @param willGroupList 需要分组的字段
     * @return 结果
     */
    public static <T> String getPropertyValue(T item, List<String> willGroupList) {
        try {
            ArrayList<String> groupList = new ArrayList<>();
            for (int i = 0; i < willGroupList.size(); i++) {
                String willGroupName = willGroupList.get(i);
                String methodName = "get" + willGroupName.substring(0, 1).toUpperCase() + willGroupName.substring(1);
                Object object = item.getClass().getMethod(methodName).invoke(item);
                String str = Optional.ofNullable(object).map(String::valueOf).orElse(null);
                groupList.add(str);
            }
            return StrUtil.join(StrPool.COMMA, groupList);
        } catch (Exception e) {
            throw new RuntimeException("获取属性值失败", e);
        }
    }

}
